package com.wang.cloud.manage.service.impl;


import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wang.cloud.common.core.exception.ServiceException;
import com.wang.cloud.common.mysql.utils.PageUtils;
import com.wang.cloud.manage.convert.MenuConvertor;
import com.wang.cloud.manage.domain.co.MenuPageCo;
import com.wang.cloud.manage.domain.entity.MenuEntity;
import com.wang.cloud.manage.domain.vo.MenuPageVo;
import com.wang.cloud.manage.domain.vo.MenuTreeVo;
import com.wang.cloud.manage.domain.vo.MenuVo;
import com.wang.cloud.manage.enums.MenuTypeEnums;
import com.wang.cloud.manage.mapper.MenuMapper;
import com.wang.cloud.manage.service.IMenuService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static cn.hutool.core.util.ObjectUtil.isEmpty;
import static cn.hutool.core.util.ObjectUtil.isNotEmpty;

/**
 * <p>
 * 系统-菜单权限表 服务实现类
 * </p>
 *
 * @author wy
 * @since 2024-07-15
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, MenuEntity> implements IMenuService {

    @Resource
    private MenuConvertor convertor;

    @Override
    public IPage<MenuPageVo> page(MenuPageCo pageCo) {
        return this.lambdaQuery()
                .eq(ObjectUtil.isNotEmpty(pageCo.getParentId()), MenuEntity::getParentId, pageCo.getParentId())
                .eq(ObjectUtil.isNotEmpty(pageCo.getAncestors()), MenuEntity::getAncestors, pageCo.getAncestors())
                .eq(ObjectUtil.isNotEmpty(pageCo.getLv()), MenuEntity::getLv, pageCo.getLv())
                .eq(ObjectUtil.isNotEmpty(pageCo.getMenuName()), MenuEntity::getMenuName, pageCo.getMenuName())
                .eq(ObjectUtil.isNotEmpty(pageCo.getPath()), MenuEntity::getPath, pageCo.getPath())
                .eq(ObjectUtil.isNotEmpty(pageCo.getIcon()), MenuEntity::getIcon, pageCo.getIcon())
                .eq(ObjectUtil.isNotEmpty(pageCo.getMenuType()), MenuEntity::getMenuType, pageCo.getMenuType())
                .eq(ObjectUtil.isNotEmpty(pageCo.getStatus()), MenuEntity::getStatus, pageCo.getStatus())
                .eq(ObjectUtil.isNotEmpty(pageCo.getOrderNum()), MenuEntity::getOrderNum, pageCo.getOrderNum())
                .eq(ObjectUtil.isNotEmpty(pageCo.getPerms()), MenuEntity::getPerms, pageCo.getPerms())
                .eq(ObjectUtil.isNotEmpty(pageCo.getComponent()), MenuEntity::getComponent, pageCo.getComponent())
                .eq(ObjectUtil.isNotEmpty(pageCo.getIsFrame()), MenuEntity::getIsFrame, pageCo.getIsFrame())
                .eq(ObjectUtil.isNotEmpty(pageCo.getIsCache()), MenuEntity::getIsCache, pageCo.getIsCache())
                .eq(ObjectUtil.isNotEmpty(pageCo.getVisible()), MenuEntity::getVisible, pageCo.getVisible())
                .eq(ObjectUtil.isNotEmpty(pageCo.getChildNodesNum()), MenuEntity::getChildNodesNum, pageCo.getChildNodesNum())
                .select(MenuEntity::getId
                        , MenuEntity::getParentId
                        , MenuEntity::getAncestors
                        , MenuEntity::getLv
                        , MenuEntity::getMenuName
                        , MenuEntity::getPath
                        , MenuEntity::getIcon
                        , MenuEntity::getMenuType
                        , MenuEntity::getStatus
                        , MenuEntity::getOrderNum
                        , MenuEntity::getPerms
                        , MenuEntity::getComponent
                        , MenuEntity::getIsFrame
                        , MenuEntity::getIsCache
                        , MenuEntity::getVisible
                        , MenuEntity::getChildNodesNum
                )
                .page(PageUtils.getPage(pageCo))
                .convert(convertor::entityToPageVo);
    }

    @Override
    public MenuVo getInfo(Long id) {
        MenuEntity entity = this.getById(id);
        return convertor.entityToVo(entity);
    }

    @Override
    public List<MenuTreeVo> getTree(String status) {
        return getTree(status, null);
    }

    @Override
    public List<MenuVo> getSubBaseListByParentId(Long parentId) {
        List<MenuEntity> list = this.lambdaQuery()
                .eq(MenuEntity::getParentId, parentId)
                .select(MenuEntity::getId, MenuEntity::getParentId,
                        MenuEntity::getMenuName, MenuEntity::getPath, MenuEntity::getIcon,
                        MenuEntity::getMenuType, MenuEntity::getStatus, MenuEntity::getOrderNum,
                        MenuEntity::getComponent, MenuEntity::getPerms, MenuEntity::getChildNodesNum
                )
                .orderByAsc(MenuEntity::getOrderNum, MenuEntity::getId)
                .list();
        return list.stream()
                .map(convertor::entityToVo)
                .collect(Collectors.toList());
    }

    @Override
    public List<MenuTreeVo> getTree(String status, Collection<Long> menuIds) {
        List<MenuEntity> list = this.lambdaQuery()
                .in(ObjectUtil.isNotEmpty(menuIds), MenuEntity::getId, menuIds)
                .eq(ObjectUtil.isNotEmpty(status), MenuEntity::getStatus, status)
                .select(MenuEntity::getId
                        , MenuEntity::getParentId
                        , MenuEntity::getAncestors
                        , MenuEntity::getLv
                        , MenuEntity::getMenuName
                        , MenuEntity::getPath
                        , MenuEntity::getIcon
                        , MenuEntity::getMenuType
                        , MenuEntity::getStatus
                        , MenuEntity::getOrderNum
                        , MenuEntity::getPerms
                        , MenuEntity::getComponent
                        , MenuEntity::getIsFrame
                        , MenuEntity::getIsCache
                        , MenuEntity::getVisible
                        , MenuEntity::getChildNodesNum
                )
                .orderByAsc(MenuEntity::getOrderNum)
                .list();
        return convertor.buildTree(list);
    }

    private void checkTypeAndPath(Long parentId, Long menuId, String menuType, String path) {
        MenuTypeEnums typeEnums = MenuTypeEnums.getEnum(menuType);
        if (Objects.isNull(typeEnums)) {
            throw new ServiceException("非法的路由类型");
        }
        switch (typeEnums) {
            case C:
                if (ObjectUtil.isEmpty(path)) {
                    throw new ServiceException("请输入路由地址");
                }
                break;
            case F:
                if (Objects.isNull(parentId) || Objects.equals(0L, parentId)) {
                    throw new ServiceException("按钮必须要有上级路由");
                }
                if (Objects.nonNull(menuId) && this.hasSubMenu(menuId, null)) {
                    throw new ServiceException("存在下级路由，不能修改为按钮");
                }
                break;
            default:
                ;
        }
        if (this.pathIsRepeat(path, menuId)) {
            throw new ServiceException("路由地址已存在");
        }
    }


    @Override
    public void del(Long id) {
        this.removeById(id);
    }

    @Override
    public void updateChildrenMenuNum(Long id) {
        if (Objects.isNull(id) || Objects.equals(0L, id)) {
            return;
        }
        Long count = this.lambdaQuery()
                .eq(MenuEntity::getParentId, id)
                .count();
        MenuEntity entity = new MenuEntity();
        entity.setChildNodesNum(count.intValue());
        entity.setId(id);
        this.updateById(entity);
    }

    @Override
    public boolean hasSubMenu(Long id, String status) {
        boolean exists = this.lambdaQuery()
                .eq(MenuEntity::getParentId, id)
                .eq(isNotEmpty(status), MenuEntity::getStatus, status)
                .last(" LIMIt 1 ")
                .exists();
        return exists;
    }


    @Override
    public Boolean pathIsRepeat(String path, Long menuId) {
        if (isEmpty(path)) {
            return false;
        }
        return this.lambdaQuery()
                .eq(MenuEntity::getPath, path)
                .ne(Objects.nonNull(menuId), MenuEntity::getId, menuId)
                .last(" LIMIT 1")
                .exists();
    }


    @Override
    public Boolean allExists(Collection<Long> menuIds) {
        if (isEmpty(menuIds)) {
            return Boolean.TRUE;
        }
        HashSet<Long> ids = new HashSet<>(menuIds);
        Long count = this.lambdaQuery()

                .in(MenuEntity::getId, ids)
                .count();
        return ids.size() == count.intValue();
    }
}
